/*
 * Copyright (C) 2008,2009,2010,2011  Paulo Cesar Pereira de Andrade.
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * Authors:
 *	Paulo Cesar Pereira de Andrade
 */

#include "exl.h"

/*   routines are for handling constant expressions during parse time
 * these are parse only objects, and are guaranteed to not be shared,
 * and can be modified.
 */

/*
 * Prototypes
 */
static eint32_t
shift_power(evalue_t *v);

static void
shift_mul(evalue_t *l, eint32_t o);

static void
shift_div(evalue_t *l, eint32_t o);

static void
shift_shl(evalue_t *l, eint32_t o);

static void
shift_shr(evalue_t *l, eint32_t o);

static void
number_canonicalize(evalue_t *l);

static eobject_t
new_mpz_d(efloat_t d);

static eobject_t
new_mpz_r(empr_t r);

static eobject_t
new_mpq_i(eint_t si);

static eobject_t
new_mpq_z(empz_t z);

static eobject_t
new_mpr_si(eint_t si);

static eobject_t
new_mpr_d(efloat_t d);

static eobject_t
new_mpr_z(empz_t z);

static eobject_t
new_mpr_q(empq_t q);

static eobject_t
new_cqq_i_i(eint_t re, eint_t im);

static eobject_t
new_cqq_z_z(empz_t re, empz_t im);

static eobject_t
new_cqq_q_q(empq_t re, empq_t im);

static eobject_t
new_mpc_i_i(eint_t re, eint_t im);

static eobject_t
new_mpc_d_d(efloat_t re, efloat_t im);

static eobject_t
new_mpc_z(empz_t z);

static eobject_t
new_mpc_q_q(empq_t re, empq_t im);

static eobject_t
new_mpc_r_r(empr_t re, empr_t im);

/*
 * Implementation
 */
ebool_t
enumber_get(eobject_t o, evalue_t *n)
{
    etype_t	t;

    switch ((t = etype(o))) {
	case t_void:
	    n->t = t_int;
	    n->v.i = 0;
	    break;
	case t_fixnum:
	    n->t = t_int;
	    n->v.i = eget_fixnum(o);
	    break;
	case t_int:	case t_float:
	    n->t = t;
	    n->v.i = *(eint_t *)o;
	    break;
	case t_mpz:	case t_mpq:	case t_mpr:
	case t_cqq:	case t_mpc:
	    n->t = t;
	    n->v.o = o;
	    break;
	case t_cdd:
	    n->t = t;
	    n->v.cdd = *(ecdd_t *)o;
	    break;
	default:
	    return (false);
    }
    return (true);
}

void
enumber_coerce(evalue_t *l, evalue_t *r)
{
    v_enter();

    v_check(1);
    switch (l->t) {
	case t_int:
	    switch (r->t) {
		case t_int:			/* nothing */
		    break;
		case t_float:			/* l: i -> d */
		    l->v.d = l->v.i;
		    l->t = t_float;
		    break;
		case t_mpz:			/* l: i -> Z */
		    enew_mpz_i(&l->v.o, l->v.i);
		    l->t = t_mpz;
		    break;
		case t_mpq:			/* l: i -> Q */
		    l->v.mpq = new_mpq_i(l->v.i);
		    l->t = t_mpq;
		    break;
		case t_mpr:			/* l: i -> R */
		    l->v.mpr = new_mpr_si(l->v.i);
		    l->t = t_mpr;
		    break;
		case t_cdd:			/* l: i -> dd */
		    real(l->v.cdd) = l->v.i;
		    imag(l->v.cdd) = 0;
		    l->t = t_cdd;
		    break;
		case t_cqq:			/* l: i -> qq */
		    l->v.cqq = new_cqq_i_i(l->v.i, 0);
		    l->t = t_cqq;
		    break;
		default:			/* l: i -> cc */
		    l->v.mpc = new_mpc_i_i(l->v.i, 0);
		    l->t = t_mpc;
		    break;
	    }
	    break;
	case t_float:
	    switch (r->t) {
		case t_int:			/* r: i -> d */
		    r->v.d = r->v.i;
		    r->t = t_float;
		    break;
		case t_float:			/* nothing */
		    break;
		case t_mpz:			/* r: Z -> d */
		    r->v.d = mpz_get_d(r->v.mpz);
		    r->t = t_float;
		    break;
		case t_mpq:			/* r: Q -> d */
		    r->v.d = mpq_get_d(r->v.mpq);
		    r->t = t_float;
		    break;
		case t_mpr:			/* l: d -> R */
		    l->v.mpr = new_mpr_d(l->v.d);
		    l->t = t_mpr;
		    break;
		case t_cdd:			/* l: d -> dd */
		    real(l->v.cdd) = l->v.d;
		    imag(l->v.cdd) = 0;
		    l->t = t_cdd;
		    break;
		case t_cqq:			/* l: d -> dd, r: qq -> dd */
		    imag(l->v.cdd) = 0;
		    l->t = t_cdd;
		    imag(r->v.cdd) = mpq_get_d(cqq_imagref(r->v.cqq));
		    real(r->v.cdd) = mpq_get_d(cqq_realref(r->v.cqq));
		    r->t = t_cdd;
		    break;
		default:			/* l: d -> cc */
		    l->v.mpc = new_mpc_d_d(l->v.d, 0);
		    l->t = t_mpc;
		    break;
	    }
	    break;
	case t_mpz:
	    switch (r->t) {
		case t_int:			/* r: i -> Z */
		    enew_mpz_i(&r->v.o, r->v.i);
		    r->t = t_mpz;
		    break;
		case t_float:			/* l: Z -> d */
		    l->v.d = mpz_get_d(l->v.mpz);
		    l->t = t_float;
		    break;
		case t_mpz:			/* nothing */
		    break;
		case t_mpq:			/* l: Z -> Q */
		    l->v.mpq = new_mpq_z(l->v.mpz);
		    l->t = t_mpq;
		    break;
		case t_mpr:			/* l: Z -> R */
		    l->v.mpr = new_mpr_z(l->v.mpz);
		    l->t = t_mpr;
		    break;
		case t_cdd:			/* l: Z -> dd */
		    real(l->v.cdd) = mpz_get_d(l->v.mpz);
		    imag(l->v.cdd) = 0;
		    l->t = t_cdd;
		    break;
		case t_cqq:			/* l: Z -> qq */
		    l->v.cqq = new_cqq_z_z(l->v.mpz, null);
		    l->t = t_cqq;
		    break;
		default:			/* l: Z -> cc */
		    l->v.mpc = new_mpc_z(l->v.mpz);
		    l->t = t_mpc;
		    break;
	    }
	    break;
	case t_mpq:
	    switch (r->t) {
		case t_int:			/* r: i -> Q */
		    r->v.mpq = new_mpq_i(r->v.i);
		    r->t = t_mpq;
		    break;
		case t_float:			/* l: Q -> d */
		    l->v.d = mpq_get_d(l->v.mpq);
		    l->t = t_float;
		    break;
		case t_mpz:			/* r: Z -> Q */
		    r->v.mpq = new_mpq_z(r->v.mpz);
		    r->t = t_mpq;
		    break;
		case t_mpq:			/* nothing */
		    break;
		case t_mpr:			/* l: Q -> R */
		    l->v.mpr = new_mpr_q(l->v.mpq);
		    l->t = t_mpr;
		    break;
		case t_cdd:			/* l: Q -> dd */
		    real(l->v.cdd) = mpq_get_d(l->v.mpq);
		    imag(l->v.cdd) = 0;
		    l->t = t_cdd;
		    break;
		case t_cqq:			/* l: Q -> qq */
		    l->v.cqq = new_cqq_q_q(l->v.mpq, null);
		    l->t = t_cqq;
		    break;
		default:			/* l: Q -> cc */
		    l->v.mpc = new_mpc_q_q(l->v.mpq, null);
		    l->t = t_mpc;
		    break;
	    }
	    break;
	case t_mpr:
	    switch (r->t) {
		case t_int:			/* r: i -> R */
		    r->v.mpr = new_mpr_si(r->v.i);
		    r->t = t_mpr;
		    break;
		case t_float:			/* r: d -> R */
		    r->v.mpr = new_mpr_d(r->v.d);
		    r->t = t_mpr;
		    break;
		case t_mpz:			/* r: Z -> R */
		    r->v.mpr = new_mpr_z(r->v.mpz);
		    r->t = t_mpr;
		    break;
		case t_mpq:			/* r: Q -> R */
		    r->v.mpr = new_mpr_q(r->v.mpq);
		    r->t = t_mpr;
		    break;
		case t_mpr:			/* nothing */
		    break;
		case t_cdd:			/* l: R -> cc, r: dd -> cc */
		    l->v.mpc = new_mpc_r_r(l->v.mpr, null);
		    v_push(l->v.mpc);
		    l->t = t_mpc;
		    r->v.mpc = new_mpc_d_d(real(r->v.cdd), imag(r->v.cdd));
		    r->t = t_mpc;
		    break;
		case t_cqq:			/* l: R -> cc, r: q -> cc */
		    l->v.mpc = new_mpc_r_r(l->v.mpr, null);
		    v_push(l->v.mpc);
		    l->t = t_mpc;
		    r->v.mpc = new_mpc_q_q(cqq_realref(r->v.cqq),
					   cqq_imagref(r->v.cqq));
		    r->t = t_mpc;
		    break;
		default:			/* l: R -> cc */
		    l->v.mpc = new_mpc_r_r(l->v.mpr, null);
		    l->t = t_mpc;
		    break;
	    }
	    break;
	case t_cdd:
	    switch (r->t) {
		case t_int:			/* r: i -> dd */
		    real(r->v.cdd) = r->v.i;
		    imag(r->v.cdd) = 0;
		    r->t = t_cdd;
		    break;
		case t_float:			/* r: d -> dd */
		    imag(r->v.cdd) = 0;
		    r->t = t_cdd;
		    break;
		case t_mpz:			/* r: Z -> dd */
		    real(r->v.cdd) = mpz_get_d(r->v.mpz);
		    imag(r->v.cdd) = 0;
		    r->t = t_cdd;
		    break;
		case t_mpq:			/* r: Q -> dd */
		    real(r->v.cdd) = mpq_get_d(r->v.mpq);
		    imag(r->v.cdd) = 0;
		    r->t = t_cdd;
		    break;
		case t_mpr:			/* l: dd -> cc, r: R -> cc */
		    l->v.mpc = new_mpc_d_d(real(l->v.cdd), imag(l->v.cdd));
		    v_push(l->v.mpc);
		    l->t = t_mpc;
		    r->v.mpc = new_mpc_r_r(r->v.mpr, null);
		    r->t = t_mpc;
		    break;
		case t_cdd:			/* nothing */
		    break;
		case t_cqq:			/* r: qq -> dd */
		    imag(r->v.cdd) = mpq_get_d(cqq_imagref(r->v.cqq));
		    real(r->v.cdd) = mpq_get_d(cqq_realref(r->v.cqq));
		    r->t = t_cdd;
		    break;
		default:			/* l: dd -> cc */
		    l->v.mpc = new_mpc_d_d(real(l->v.cdd), imag(l->v.cdd));
		    l->t = t_mpc;
		    break;
	    }
	    break;
	case t_cqq:
	    switch (r->t) {
		case t_int:			/* r: i -> qq */
		    r->v.cqq = new_cqq_i_i(r->v.i, 0);
		    r->t = t_cqq;
		    break;
		case t_float:			/* l: qq -> dd, r: d -> dd */
		    imag(l->v.cdd) = mpq_get_d(cqq_imagref(l->v.cqq));
		    real(l->v.cdd) = mpq_get_d(cqq_realref(l->v.cqq));
		    l->t = t_cdd;
		    imag(r->v.cdd) = 0;;
		    r->t = t_cdd;
		    break;
		case t_mpz:			/* r: Z -> qq */
		    r->v.cqq = new_cqq_z_z(r->v.mpz, null);
		    r->t = t_cqq;
		    break;
		case t_mpq:			/* r: Q -> qq */
		    r->v.cqq = new_cqq_q_q(r->v.mpq, null);
		    r->t = t_cqq;
		    break;
		case t_mpr:			/* l: qq -> cc, r: r -> cc */
		    l->v.mpc = new_mpc_q_q(cqq_realref(l->v.cqq),
					   cqq_imagref(l->v.cqq));
		    v_push(l->v.mpc);
		    l->t = t_mpc;
		    r->v.mpc = new_mpc_r_r(r->v.mpr, null);
		    r->t = t_mpc;
		    break;
		case t_cdd:			/* l: qq -> dd */
		    imag(l->v.cdd) = mpq_get_d(cqq_imagref(l->v.cqq));
		    real(l->v.cdd) = mpq_get_d(cqq_realref(l->v.cqq));
		    l->t = t_cdd;
		    break;
		case t_cqq:			/* nothing */
		    break;
		default:			/* l: dd -> cc */
		    l->v.mpc = new_mpc_q_q(cqq_realref(l->v.cqq),
					   cqq_imagref(l->v.cqq));
		    l->t = t_mpc;
		    break;
	    }
	    break;
	default:
	    switch (r->t) {
		case t_int:			/* r: i -> cc */
		    r->v.mpc = new_mpc_i_i(r->v.i, 0);
		    r->t = t_mpc;
		    break;
		case t_float:			/* r: d -> cc */
		    r->v.mpc = new_mpc_d_d(r->v.d, 0);
		    r->t = t_mpc;
		    break;
		case t_mpz:			/* r: Z -> cc */
		    r->v.mpc = new_mpc_z(r->v.mpz);
		    r->t = t_mpc;
		    break;
		case t_mpq:			/* r: Q -> cc */
		    r->v.mpc = new_mpc_q_q(r->v.mpq, null);
		    r->t = t_mpc;
		    break;
		case t_mpr:			/* r: R -> cc */
		    r->v.mpc = new_mpc_r_r(r->v.mpr, null);
		    r->t = t_mpc;
		    break;
		case t_cdd:			/* r: dd -> cc */
		    r->v.mpc = new_mpc_d_d(real(r->v.cdd), imag(r->v.cdd));
		    r->t = t_mpc;
		    break;
		case t_cqq:			/* r: qq -> cc */
		    r->v.mpc = new_mpc_q_q(cqq_realref(r->v.cqq),
					   cqq_imagref(r->v.cqq));
		    r->t = t_mpc;
		    break;
		default:			/* nothing */
		    break;
	    }
	    break;
    }

    v_leave();
}

eobject_t
enumber_create(evalue_t *n)
{
    eobject_t	o;
    v_enter();

    v_check(2);
    switch (n->t) {
	case t_int:
	    einteger(&o, n->v.i);
	    break;
	case t_float:
	    enew_float(&o, n->v.d);
	    break;
	case t_cdd:
	    enew_cdd(&o, n->v.cdd);
	    break;
	default:
	    o = n->v.o;
	    break;
    }

    v_leave();
    return (o);
}

ebool_t
enumber_offset(eobject_t object, eint32_t *offset)
{
    evalue_t	n;
    efloat_t	d;
    eint_t	si;

    if (enumber_get(object, &n)) {
	switch (n.t) {
	    case t_int:
		if (n.v.i < 0 || n.v.i > most_positive_fix32)
		    goto offset_fail;
		*offset = n.v.i;
		break;
	    case t_float:
		if (n.v.d < 0 || n.v.d > most_positive_fix32)
		    goto offset_fail;
		*offset = n.v.d;
		break;
	    case t_mpz:
		if (mpz_fits_slong_p(n.v.mpz)) {
		    si = empz_get_i(n.v.mpz);
		    if (si < 0 || si > most_positive_fix32)
			goto offset_fail;
		    *offset = si;
		}
		else
		    goto offset_fail;
		break;
	    case t_mpq:
		if (mpz_fits_slong_p(mpq_numref(n.v.mpq)) &&
		    mpz_fits_slong_p(mpq_denref(n.v.mpq))) {
		    d = mpq_get_d(n.v.mpq);
		    if (d < 0 || d > most_positive_fix32)
			goto offset_fail;
		    *offset = d;
		}
		break;
	    case t_mpr:
		if (mpfr_fits_slong_p(n.v.mpr, GMP_RNDZ)) {
		    si = empr_get_i(n.v.mpr);
		    if (si < 0 || si > most_positive_fix32)
			goto offset_fail;
		    *offset = si;
		}
		else
		    goto offset_fail;
		break;
	    default:
		ecfg_error(parse, "not a real number");
	}

	return (true);
    }

    return (false);
offset_fail:
    ecfg_error(parse, "offset out of bounds");
}

ebool_t
eintfix_p(eobject_t object)
{
    switch (etype(object)) {
	case t_void:
	case t_fixnum:	case t_int:
	    return (true);
	default:
	    return (false);
    }
}

ebool_t
einteger_p(eobject_t object)
{
    switch (etype(object)) {
	case t_void:
	case t_fixnum:	case t_int:	case t_mpz:
	    return (true);
	default:
	    return (false);
    }
}

ebool_t
enumber_p(eobject_t object)
{
    switch (etype(object)) {
	case t_void:
	case t_fixnum:	case t_int:	case t_float:
	case t_mpz:	case t_mpq:	case t_mpr:	case t_mpc:
	case t_cdd:	case t_cqq:
	    return (true);
	default:
	    return (false);
    }
}

ebool_t
efalse_p(eobject_t object)
{
    evalue_t	n;

    if (object == null)
	return (true);
    if (!enumber_get(object, &n))
	return (false);
    switch (n.t) {
	case t_int:	return (n.v.i == 0);
	case t_float:	return (n.v.d == 0.0);
	case t_mpr:	return (mpfr_zero_p(n.v.mpr) != 0);
	default:
#if DEBUG
	    switch (n.t) {
		case t_mpz:
		    if (mpz_sgn(n.v.mpz) == 0)
			abort();
		    break;
		case t_mpq:
		    if (mpq_sgn(n.v.mpq) == 0)
			abort();
		    break;
		case t_cdd:
		    if (real(n.v.cdd) == 0 && imag(n.v.cdd) == 0)
			abort();
		    break;
		case t_cqq:
		    if (mpq_sgn(cqq_realref(n.v.cqq)) == 0 &&
			mpq_sgn(cqq_imagref(n.v.cqq)) == 0)
			abort();
		    break;
		default:
		    if (mpfr_zero_p(mpc_realref(n.v.mpc)) &&
			mpfr_zero_p(mpc_imagref(n.v.mpc)))
			abort();
		    break;
	    }
#endif
	    return (false);
    }
}

void
enumber_andand(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:  l->v.i = l->v.i && r->v.i;				break;
	case t_float:l->v.i = l->v.d && r->v.d;				break;
	case t_mpz:  l->v.i = mpz_sgn(l->v.mpz) && mpz_sgn(r->v.mpz);	break;
	case t_mpq:  l->v.i = mpq_sgn(l->v.mpq) && mpq_sgn(r->v.mpq);	break;
	case t_mpr:  l->v.i = mpfr_sgn(l->v.mpr) && mpfr_sgn(r->v.mpr);	break;
	case t_cdd:  l->v.i = ((real(l->v.cdd) || imag(l->v.cdd)) &&
			       (real(r->v.cdd) || imag(r->v.cdd)));	break;
	case t_cqq:  l->v.i = ((mpq_sgn(cqq_realref(l->v.cqq)) ||
				mpq_sgn(cqq_imagref(l->v.cqq))) &&
			       (mpq_sgn(cqq_realref(r->v.cqq)) ||
				mpq_sgn(cqq_imagref(r->v.cqq))));	break;
	default:  l->v.i = ((mpfr_sgn(mpc_realref(l->v.mpc)) ||
			     mpfr_sgn(mpc_imagref(l->v.mpc))) &&
			    (mpfr_sgn(mpc_realref(r->v.mpc)) ||
			     mpfr_sgn(mpc_imagref(r->v.mpc))));		break;
    }
    l->t = t_int;
}

void
enumber_oror(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:  l->v.i = l->v.i || r->v.i;				break;
	case t_float:l->v.i = l->v.d || r->v.d;				break;
	case t_mpr:  l->v.i = mpfr_sgn(l->v.mpr) || mpfr_sgn(r->v.mpr);	break;
	default:
#if DEBUG
	    /* coercion may have created only one false value */
	    switch (l->t) {
		case t_mpz:
		    l->v.i = mpz_sgn(l->v.mpz) || mpz_sgn(r->v.mpz);
		    break;
		case t_mpq:
		    l->v.i = mpq_sgn(l->v.mpq) || mpq_sgn(r->v.mpq);
		    break;
		case t_cdd:
		    l->v.i = (real(l->v.cdd) || imag(l->v.cdd) ||
			      real(r->v.cdd) || imag(r->v.cdd));
		    break;
		case t_cqq:
		    l->v.i = (mpq_sgn(cqq_realref(l->v.cqq)) ||
			      mpq_sgn(cqq_imagref(l->v.cqq)) ||
			      mpq_sgn(cqq_realref(r->v.cqq)) ||
			      mpq_sgn(cqq_imagref(r->v.cqq)));
		    break;
		default:
		    l->v.i = (mpfr_sgn(mpc_realref(l->v.mpc)) ||
			      mpfr_sgn(mpc_imagref(l->v.mpc)) ||
			      mpfr_sgn(mpc_realref(r->v.mpc)) ||
			      mpfr_sgn(mpc_imagref(r->v.mpc)));
		    break;
	    }
	    assert(l->v.i == 1);
#else
	    l->v.i = 1;
#endif
	    break;
    }
    l->t = t_int;
}

void
enumber_lt(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    l->v.i = l->v.i < r->v.i;
	    break;
	case t_float:
	    l->v.i = l->v.d < r->v.d;
	    break;
	case t_mpz:
	    l->v.i = mpz_cmp(l->v.mpz, r->v.mpz) < 0;
	    break;
	case t_mpq:
	    l->v.i = mpq_cmp(l->v.mpq, r->v.mpq) < 0;
	    break;
	case t_mpr:
	    l->v.i = mpfr_less_p(l->v.mpr, r->v.mpr);
	    break;
	default:
	    ecfg_error(parse, "not a real number");
	    break;
    }
    l->t = t_int;
}

void
enumber_le(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    l->v.i = l->v.i <= r->v.i;
	    break;
	case t_float:
	    l->v.i = l->v.d <= r->v.d;
	    break;
	case t_mpz:
	    l->v.i = mpz_cmp(l->v.mpz, r->v.mpz) <= 0;
	    break;
	case t_mpq:
	    l->v.i = mpq_cmp(l->v.mpq, r->v.mpq) <= 0;
	    break;
	case t_mpr:
	    l->v.i = mpfr_lessequal_p(l->v.mpr, r->v.mpr);
	    break;
	default:
	    ecfg_error(parse, "not a real number");
	    break;
    }
    l->t = t_int;
}

void
enumber_ge(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    l->v.i = l->v.i >= r->v.i;
	    break;
	case t_float:
	    l->v.i = l->v.d >= r->v.d;
	    break;
	case t_mpz:
	    l->v.i = mpz_cmp(l->v.mpz, r->v.mpz) >= 0;
	    break;
	case t_mpq:
	    l->v.i = mpq_cmp(l->v.mpq, r->v.mpq) >= 0;
	    break;
	case t_mpr:
	    l->v.i = mpfr_greaterequal_p(l->v.mpr, r->v.mpr);
	    break;
	default:
	    ecfg_error(parse, "not a real number");
	    break;
    }
    l->t = t_int;
}

void
enumber_gt(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    l->v.i = l->v.i > r->v.i;
	    break;
	case t_float:
	    l->v.i = l->v.d > r->v.d;
	    break;
	case t_mpz:
	    l->v.i = mpz_cmp(l->v.mpz, r->v.mpz) > 0;
	    break;
	case t_mpq:
	    l->v.i = mpq_cmp(l->v.mpq, r->v.mpq) > 0;
	    break;
	case t_mpr:
	    l->v.i = mpfr_greater_p(l->v.mpr, r->v.mpr);
	    break;
	default:
	    ecfg_error(parse, "not a real number");
	    break;
    }
    l->t = t_int;
}

void
enumber_ne(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    l->v.i = l->v.i != r->v.i;
	    break;
	case t_float:
	    l->v.i = l->v.d != r->v.d;
	    break;
	case t_mpz:
	    l->v.i = mpz_cmp(l->v.mpz, r->v.mpz) != 0;
	    break;
	case t_mpq:
	    l->v.i = mpq_cmp(l->v.mpq, r->v.mpq) != 0;
	    break;
	case t_mpr:
	    l->v.i = !mpfr_equal_p(l->v.mpr, r->v.mpr);
	    break;
	case t_cdd:
	    l->v.i = l->v.cdd != r->v.cdd;
	    break;
	case t_cqq:
	    l->v.i = (mpq_cmp(cqq_realref(l->v.cqq),
			      cqq_realref(r->v.cqq)) != 0) ||
		     (mpq_cmp(cqq_imagref(l->v.cqq),
			      cqq_imagref(r->v.cqq)) != 0);
	    break;
	default:
	    l->v.i = !mpfr_equal_p(mpc_realref(l->v.mpc),
				   mpc_realref(r->v.mpc)) ||
		     !mpfr_equal_p(mpc_imagref(l->v.mpc),
				   mpc_imagref(r->v.mpc));
	    break;
    }
    l->t = t_int;
}

void
enumber_eq(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    l->v.i = l->v.i == r->v.i;
	    break;
	case t_float:
	    l->v.i = l->v.d == r->v.d;
	    break;
	case t_mpz:
	    l->v.i = mpz_cmp(l->v.mpz, r->v.mpz) == 0;
	    break;
	case t_mpq:
	    l->v.i = mpq_cmp(l->v.mpq, r->v.mpq) == 0;
	    break;
	case t_mpr:
	    l->v.i = mpfr_equal_p(l->v.mpr, r->v.mpr);
	    break;
	case t_cdd:
	    l->v.i = l->v.cdd == r->v.cdd;
	    break;
	case t_cqq:	    
	    l->v.i = mpq_cmp(cqq_realref(l->v.cqq),
			     cqq_realref(r->v.cqq)) == 0 &&
		     mpq_cmp(cqq_imagref(l->v.cqq),
			     cqq_imagref(r->v.cqq)) == 0;
	    break;
	default:
	    l->v.i = mpfr_equal_p(mpc_realref(l->v.mpc),
				  mpc_realref(r->v.mpc)) &&
		     mpfr_equal_p(mpc_imagref(l->v.mpc),
				  mpc_imagref(r->v.mpc));
	    break;
    }
    l->t = t_int;
}

void
enumber_bool(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    l->v.i = !!l->v.i;
	    break;
	case t_float:
	    l->v.i = !!l->v.d;
	    break;
	case t_mpq:
	    l->v.i = !mpq_sgn(l->v.mpq);
	    break;
	case t_mpr:
	    l->v.i = !!mpfr_zero_p(l->v.mpr);
	    break;
	default:
	    l->v.i = 1;
	    break;
    }
    l->t = t_int;
}

void
enumber_not(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    l->v.i = !l->v.i;
	    break;
	case t_float:
	    l->v.i = !l->v.d;
	    break;
	case t_mpq:
	    l->v.i = mpq_sgn(l->v.mpq) != 0;
	    break;
	case t_mpr:
	    l->v.i = !!mpfr_zero_p(l->v.mpr);
	    break;
	default:
	    l->v.i = 0;
	    break;
    }
    l->t = t_int;
}

void
einteger_and(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    l->v.i &= r->v.i;
	    break;
	case t_mpz:
	    if (ez_and_z_z(l->v.mpz, l->v.mpz, r->v.mpz)) {
		l->v.i = empz_get_i(l->v.mpz);
		l->t = t_int;
	    }
	    break;
	default:
	    ecfg_error(read, "not an integer");
    }
}

void
einteger_or(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    l->v.i |= r->v.i;
	    break;
	case t_mpz:
	    ez_or_z_z(l->v.mpz, l->v.mpz, r->v.mpz);
	    break;
	default:
	    ecfg_error(read, "not an integer");
    }
}

void
einteger_xor(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    l->v.i ^= r->v.i;
	    break;
	case t_mpz:
	    if (ez_xor_z_z(l->v.mpz, l->v.mpz, r->v.mpz)) {
		l->v.i = empz_get_i(l->v.mpz);
		l->t = t_int;
	    }
	    break;
	default:
	    ecfg_error(read, "not an integer");
    }
}

void
enumber_mul2(evalue_t *l, evalue_t *r)
{
    eint32_t	o;
    if ((o = shift_power(r))) {
	if (o > 0)
	    shift_mul(l, o);
	else
	    shift_div(l, -o);
	number_canonicalize(l);
    }
}

void
enumber_div2(evalue_t *l, evalue_t *r)
{
    eint32_t	o;
    if ((o = shift_power(r))) {
	if (o > 0)
	    shift_div(l, o);
	else
	    shift_mul(l, -o);
	number_canonicalize(l);
    }
}

void
enumber_shl(evalue_t *l, evalue_t *r)
{
    eint32_t	o;
    o = shift_power(r);
    if (o >= 0)
	shift_shl(l, o);
    else
	shift_shr(l, -o);
    number_canonicalize(l);
}

void
enumber_shr(evalue_t *l, evalue_t *r)
{
    eint32_t	o;
    o = shift_power(r);
    if (o >= 0)
	shift_shr(l, o);
    else
	shift_shl(l, -o);
    number_canonicalize(l);
}

void
einteger_com(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    l->v.i = ~l->v.i;
	    break;
	case t_mpz:
	    if (ez_com(l->v.mpz, l->v.mpz)) {
		l->v.i = empz_get_i(l->v.mpz);
		l->t = t_int;
	    }
	    break;
	default:
	    ecfg_error(read, "not an integer");
    }
}

void
enumber_add(evalue_t *l, evalue_t *r)
{
    eint_t	i;

    switch (l->t) {
	case t_int:
	    i = l->v.i;
	    l->v.i = l->v.i + r->v.i;
	    if (eadd_over_p(l->v.i, i, r->v.i)) {
		ez_add_i_i(thr_zr, i, r->v.i);
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    break;
	case t_float:
	    l->v.d = l->v.d + r->v.d;
	    break;
	case t_mpz:
	    if (ez_add_z_z(l->v.mpz, l->v.mpz, r->v.mpz)) {
		l->v.i = empz_get_i(l->v.mpz);
		l->t = t_int;
	    }
	    break;
	case t_mpq:
	    switch (eq_add_q_q(l->v.mpq, l->v.mpq, r->v.mpq)) {
		case 1:
		    l->v.i = empz_get_i(mpq_numref(l->v.mpq));
		    l->t = t_int;
		    break;
		case 0:
		    break;
		default:
		    enew_mpz(&l->v.o, mpq_numref(l->v.mpq));
		    l->t = t_mpz;
		    break;
	    }
	    break;
	case t_mpr:
	    er_add_r_r(l->v.mpr, l->v.mpr, r->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = l->v.cdd + r->v.cdd;
	    break;
	case t_cqq:
	    eqq_add_qq_qq(l->v.cqq, l->v.cqq, r->v.cqq);
	    break;
	default:
	    ecc_add_cc_cc(l->v.mpc, l->v.mpc, r->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_sub(evalue_t *l, evalue_t *r)
{
    eint_t	i;

    switch (l->t) {
	case t_int:
	    i = l->v.i;
	    l->v.i = l->v.i - r->v.i;
	    if (esub_over_p(l->v.i, i, r->v.i)) {
		ez_sub_i_i(thr_zr, i, r->v.i);
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    break;
	case t_float:
	    l->v.d = l->v.d - r->v.d;
	    break;
	case t_mpz:
	    if (ez_sub_z_z(l->v.mpz, l->v.mpz, r->v.mpz)) {
		l->v.i = empz_get_i(l->v.mpz);
		l->t = t_int;
	    }
	    break;
	case t_mpq:
	    switch (eq_sub_q_q(l->v.mpq, l->v.mpq, r->v.mpq)) {
		case 1:
		    l->v.i = empz_get_i(mpq_numref(l->v.mpq));
		    l->t = t_int;
		    break;
		case 0:
		    break;
		default:
		    enew_mpz(&l->v.o, mpq_numref(l->v.mpq));
		    l->t = t_mpz;
		    break;
	    }
	    break;
	case t_mpr:
	    er_sub_r_r(l->v.mpr, l->v.mpr, r->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd -= r->v.cdd;
	    break;
	case t_cqq:
	    eqq_sub_qq_qq(l->v.cqq, l->v.cqq, r->v.cqq);
	    break;
	default:
	    ecc_sub_cc_cc(l->v.mpc, l->v.mpc, r->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_mul(evalue_t *l, evalue_t *r)
{
    eint_t	si;
    switch (l->t) {
	case t_int:
	    si = l->v.i;
	    if ((l->v.i = ei_mul_i_i(l->v.i, r->v.i)) == MININT) {
		ez_mul_i_i(thr_zr, si, r->v.i);
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    break;
	case t_float:
	    l->v.d = l->v.d * r->v.d;
	    break;
	case t_mpz:
	    if (ez_mul_z_z(l->v.mpz, l->v.mpz, r->v.mpz)) {
		l->v.i = empz_get_i(l->v.mpz);
		l->t = t_int;
	    }
	    break;
	case t_mpq:
	    switch (eq_mul_q_q(l->v.mpq, l->v.mpq, r->v.mpq)) {
		case 1:
		    l->v.i = empz_get_i(mpq_numref(l->v.mpq));
		    l->t = t_int;
		    break;
		case 0:
		    break;
		default:
		    enew_mpz(&l->v.o, mpq_numref(l->v.mpq));
		    l->t = t_mpz;
		    break;
	    }
	    break;
	case t_mpr:
	    er_mul_r_r(l->v.mpr, l->v.mpr, r->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = l->v.cdd * r->v.cdd;
	    break;
	case t_cqq:
	    eqq_mul_qq_qq(l->v.cqq, l->v.cqq, r->v.cqq);
	    break;
	default:
	    ecc_mul_cc_cc(l->v.mpc, l->v.mpc, r->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_div(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    if (likely(l->v.i % r->v.i)) {
		eq_div_i_i(thr_qr, l->v.i, r->v.i);
		enew_mpq(&l->v.o, thr_qr);
		l->t = t_mpq;
	    }
	    else
		l->v.i = l->v.i / r->v.i;
	    break;
	case t_float:
	    l->v.d = l->v.d / r->v.d;
	    break;
	case t_mpz:
	    switch (eq_div_z_z(thr_qr, l->v.mpz, r->v.mpz)) {
		case 1:
		    l->v.i = empz_get_i(thr_zr);
		    l->t = t_int;
		    break;
		case -1:
		    enew_mpz(&l->v.o, thr_zr);
		    l->t = t_mpz;
		    break;
		default:
		    enew_mpq(&l->v.o, thr_qr);
		    l->t = t_mpq;
		    break;
	    }
	    break;
	case t_mpq:
	    switch (eq_div_q_q(l->v.mpq, l->v.mpq, r->v.mpq)) {
		case 1:
		    l->v.i = empz_get_i(mpq_numref(l->v.mpq));
		    l->t = t_int;
		    break;
		case 0:
		    break;
		default:
		    enew_mpz(&l->v.o, mpq_numref(l->v.mpq));
		    l->t = t_mpz;
		    break;
	    }
	    break;
	case t_mpr:
	    er_div_r_r(l->v.mpr, l->v.mpr, r->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = l->v.cdd / r->v.cdd;
	    break;
	case t_cqq:
	    eqq_div_qq_qq(l->v.cqq, l->v.cqq, r->v.cqq);
	    break;
	default:
	    ecc_div_cc_cc(l->v.mpc, l->v.mpc, r->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_trunc2(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    l->v.i /= r->v.i;
	    break;
	case t_float:
	    if ((l->v.i = ez_trunc_d(thr_zr, l->v.d / r->v.d)) != MININT)
		l->t = t_int;
	    else {
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    break;
	case t_mpz:
	    if (ez_trunc_z_z(l->v.mpz, l->v.mpz, r->v.mpz)) {
		l->v.i = empz_get_i(l->v.mpz);
		l->t = t_int;
	    }
	    break;
	case t_mpq:
	    if ((l->v.i = ez_trunc_q_q(thr_zr, l->v.mpq, r->v.mpq)) != MININT)
		l->t = t_int;
	    else {
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    break;
	case t_mpr:
	    if ((l->v.i = ez_trunc_r_r(thr_zr, l->v.mpr, r->v.mpr)) != MININT)
		l->t = t_int;
	    else {
		l->v.mpz = new_mpz_r(thr_rr);
		l->t = t_mpz;
	    }
	    break;
	default:
	    ecfg_error(read, "not a real number");
    }
}

void
enumber_rem(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    l->v.i %= r->v.i;
	    break;
	case t_float:
	    l->v.d = fmod(l->v.d, r->v.d);
	    break;
	case t_mpz:
	    if (ez_rem_z_z(l->v.mpz, l->v.mpz, r->v.mpz)) {
		l->v.i = empz_get_i(l->v.mpz);
		l->t = t_int;
	    }
	    break;
	case t_mpq:
	    switch (eq_rem_q_q(l->v.mpq, l->v.mpq, r->v.mpq)) {
		case 1:
		    l->v.i = empz_get_i(mpq_numref(l->v.mpq));
		    l->t = t_int;
		    break;
		case 0:
		    break;
		default:
		    enew_mpz(&l->v.o, mpq_numref(l->v.mpq));
		    l->t = t_mpz;
		    break;
	    }
	    break;
	case t_mpr:
	    er_rem_r_r(l->v.mpr, l->v.mpr, r->v.mpr);
 	    break;
	default:
	    ecfg_error(read, "not a real number");
    }
    number_canonicalize(l);
}

void
enumber_atan2(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		l->v.d = atan2(l->v.i, r->v.i);
		l->t = t_float;
	    }
	    else {
		er_atan2_i_i(thr_rr, l->v.i, r->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_float:
	    l->v.d = atan2(l->v.d, r->v.d);
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.d = ed_atan2_z_z(l->v.mpz, r->v.mpz);
		l->t = t_float;
	    }
	    else {
		er_atan2_z_z(thr_rr, l->v.mpz, r->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		l->v.d = ed_atan2_q_q(l->v.mpq, r->v.mpq);
		l->t = t_float;
	    }
	    else {
		er_atan2_q_q(thr_rr, l->v.mpq, r->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpr:
	    er_atan2_r_r(l->v.mpr, l->v.mpr, r->v.mpr);
	    break;
	    /* Note that these zero tests should only be required here,
	     * because of the type conversion, as everywhere else, when
	     * the imag part becomes zero, the object is converted
	     * back to a real number */
	case t_cdd:
	    if (real(l->v.cdd) == 0.0 && imag(l->v.cdd) == 0.0) {
		l->v.d = real(r->v.cdd) >= 0.0 ? 0.0 : M_PI;
		l->t = t_float;
	    }
	    else if (real(r->v.cdd) == 0.0 && imag(r->v.cdd) == 0.0) {
		l->v.d = real(l->v.cdd) >= 0.0 ? M_PI_2 : -M_PI_2;
		l->t = t_float;
	    }
	    else
		l->v.cdd = catan(l->v.cdd / r->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		if (mpq_sgn(cqq_realref(l->v.cqq)) == 0 &&
		    mpq_sgn(cqq_imagref(l->v.cqq)) == 0) {
		    l->v.d = mpq_sgn(cqq_realref(r->v.cqq)) >= 0 ?
			0.0 : M_PI;
		    l->t = t_float;
		}
		else if (mpq_sgn(cqq_realref(r->v.cqq)) == 0 &&
			 mpq_sgn(cqq_imagref(r->v.cqq)) == 0) {
		    l->v.d = mpq_sgn(cqq_realref(l->v.cqq)) >= 0 ?
			M_PI_2 : -M_PI_2;
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_atan2_qq_qq(l->v.cqq, r->v.cqq);
		    l->t = t_cdd;
		}
	    }
	    else {
		if (mpq_sgn(cqq_realref(l->v.cqq)) == 0 &&
		    mpq_sgn(cqq_imagref(l->v.cqq)) == 0) {
		    if (mpq_sgn(cqq_realref(r->v.cqq)) >= 0)
			mpfr_set_ui(thr_rr, 0, thr_rnd);
		    else
			mpfr_const_pi(thr_rr, thr_rnd);
		    enew_mpr(&l->v.o, thr_rr);
		    l->t = t_mpr;
		}
		else if (mpq_sgn(cqq_realref(r->v.cqq)) == 0 &&
			 mpq_sgn(cqq_imagref(r->v.cqq)) == 0) {
		    if (mpq_sgn(cqq_realref(l->v.cqq)) < 0) {
			mpfr_const_pi(thr_rr, thr_rnd);
			mpfr_neg(thr_rr, thr_rr, thr_rnd);
		    }
		    else
			mpfr_const_pi(thr_rr, thr_rnd);
		    enew_mpr(&l->v.o, thr_rr);
		    mpfr_div_2exp(l->v.mpr, l->v.mpr, 1, thr_rnd);
		    l->t = t_mpr;
		}
		else {
		    ecc_atan2_qq_qq(thr_c, l->v.cqq, r->v.cqq);
		    enew_mpc(&l->v.o, thr_c);
		    l->t = t_mpc;
		}
	    }
	    break;
	default:
	    if (mpfr_zero_p(mpc_realref(l->v.mpc)) &&
		mpfr_zero_p(mpc_imagref(l->v.mpc))) {
		if (mpfr_sgn(mpc_realref(r->v.mpc)) >= 0)
		    mpfr_set_ui(thr_rr, 0, thr_rnd);
		else
		    mpfr_const_pi(thr_rr, thr_rnd);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else if (mpfr_zero_p(mpc_realref(r->v.mpc)) &&
		     mpfr_zero_p(mpc_imagref(r->v.mpc))) {
		if (mpfr_sgn(mpc_realref(l->v.mpc)) < 0) {
		    mpfr_const_pi(thr_rr, thr_rnd);
		    mpfr_neg(thr_rr, thr_rr, thr_rnd);
		}
		else
		    mpfr_const_pi(thr_rr, thr_rnd);
		enew_mpr(&l->v.o, thr_rr);
		mpfr_div_2exp(l->v.mpr, l->v.mpr, 1, thr_rnd);
		l->t = t_mpr;
	    }
	    else
		ecc_atan2_cc_cc(l->v.mpc, l->v.mpc, r->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_pow(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		l->v.d = ed_pow_i_i(l->v.i, r->v.i);
		l->t = t_float;
	    }
	    else {
		er_pow_i_i(thr_rr, l->v.i, r->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_float:
	    if (finite(l->v.d) && l->v.d < 0.0 &&
		finite(r->v.d) && rint(r->v.d) != r->v.d) {
		l->v.cdd = edd_pow_d_d(l->v.d, r->v.d);
		l->t = t_cdd;
	    }
	    else
		l->v.d = ed_pow_d_d(l->v.d, r->v.d);
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.d = ed_pow_z_z(l->v.mpz, r->v.mpz);
		l->t = t_float;
	    }
	    else {
		er_pow_z_z(thr_rr, l->v.mpz, r->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		if (mpq_sgn(l->v.mpq) < 0) {
		    l->v.cdd = edd_pow_q_q(l->v.mpq, r->v.mpq);
		    l->t = t_cdd;
		}
		else {
		    l->v.d = ed_pow_q_q(l->v.mpq, r->v.mpq);
		    l->t = t_float;
		}
	    }
	    else if (mpq_sgn(l->v.mpq) < 0) {
		ecc_pow_q_q(thr_c, l->v.mpq, r->v.mpq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    else {
		er_pow_q_q(thr_rr, l->v.mpq, r->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpr:
	    if (mpfr_number_p(l->v.mpr) && mpfr_sgn(l->v.mpr) < 0 &&
		mpfr_number_p(r->v.mpr) && !mpfr_integer_p(r->v.mpr)) {
		ecc_pow_r_r(thr_c, l->v.mpr, r->v.mpr);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    else
		er_pow_r_r(l->v.mpr, l->v.mpr, r->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = edd_pow_dd_dd(l->v.cdd, r->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_pow_qq_qq(l->v.cqq, r->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_pow_qq_qq(thr_c, l->v.cqq, r->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_pow_cc_cc(l->v.mpc, l->v.mpc, r->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_hypot(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		l->v.d = ed_hypot_i_i(l->v.i, r->v.i);
		l->t = t_float;
	    }
	    else {
		er_hypot_i_i(thr_rr, l->v.i, r->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_float:
	    l->v.d = ed_hypot_d_d(l->v.d, r->v.d);
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.d = ed_hypot_z_z(l->v.mpz, r->v.mpz);
		l->t = t_float;
	    }
	    else {
		er_hypot_z_z(thr_rr, l->v.mpz, r->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		l->v.d = ed_hypot_q_q(l->v.mpq, r->v.mpq);
		l->t = t_float;
	    }
	    else {
		er_hypot_q_q(thr_rr, l->v.mpq, r->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpr:
	    er_hypot_r_r(l->v.mpr, l->v.mpr, r->v.mpr);
	    break;
	case t_cdd:
	    l->v.d = ed_hypot_dd_dd(l->v.cdd, r->v.cdd);
	    l->t = t_float;
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.d = ed_hypot_qq_qq(l->v.cqq, r->v.cqq);
		l->t = t_float;
	    }
	    else {
		er_hypot_qq_qq(thr_rr, l->v.cqq, r->v.cqq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	default:
	    er_hypot_cc_cc(thr_rr, l->v.mpc, r->v.mpc);
	    enew_mpr(&l->v.o, thr_rr);
	    l->t = t_mpr;
	    break;
    }
}

void
enumber_complex(evalue_t *l, evalue_t *r)
{
    switch (l->t) {
	case t_int:
	    l->v.cqq = new_cqq_i_i(l->v.i, r->v.i);
	    l->t = t_cqq;
	    break;
	case t_float:
	    imag(l->v.cdd) = r->v.d;
	    l->t = t_cdd;
	    break;
	case t_mpz:
	    l->v.cqq = new_cqq_z_z(l->v.mpz, r->v.mpz);
	    l->t = t_cqq;
	    break;
	case t_mpq:
	    l->v.cqq = new_cqq_q_q(l->v.mpq, r->v.mpq);
	    l->t = t_cqq;
	    break;
	case t_mpr:
	    l->v.mpc = new_mpc_r_r(l->v.mpr, r->v.mpr);
	    l->t = t_mpc;
	    break;
	default:
	    ecfg_error(read, "not a real number");
    }
    number_canonicalize(l);
}

void
enumber_inv(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    l->t = t_mpq;
	    l->v.mpq = new_mpq_i(l->v.i);
	    empq_inv(l->v.mpq, l->v.mpq);
	    break;
	case t_float:
	    l->v.d = 1 / l->v.d;
	    break;
	case t_mpz:
	    l->t = t_mpq;
	    l->v.mpq = new_mpq_z(l->v.mpz);
	    empq_inv(l->v.mpq, l->v.mpq);
	case t_mpq:
	    empq_inv(l->v.mpq, l->v.mpq);
	    break;
	case t_mpr:
	    mpfr_ui_div(l->v.mpr, 1, l->v.mpr, thr_rnd);
	    break;
	case t_cdd:
	    l->v.cdd = 1 / l->v.cdd;
	    break;
	case t_cqq:
	    mpq_mul(thr_q1, cqq_imagref(l->v.cqq), cqq_imagref(l->v.cqq));
	    mpq_mul(thr_q2, cqq_realref(l->v.cqq), cqq_realref(l->v.cqq));
	    mpq_add(thr_q1, thr_q2, thr_q1);
	    mpq_neg(cqq_imagref(l->v.cqq), cqq_imagref(l->v.cqq));
	    empq_div(cqq_imagref(l->v.cqq), cqq_imagref(l->v.cqq), thr_q1);
	    empq_div(cqq_realref(l->v.cqq), cqq_realref(l->v.cqq), thr_q1);
	    break;
	default:
	    mpfr_set_ui(thr_rr, 1, thr_rnd);
	    mpc_fr_div(l->v.mpc, thr_rr, l->v.mpc, thr_rndc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_neg(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (l->v.i == MININT) {
		enew_mpz_u(&l->v.o, MININT);
		l->t = t_mpz;
	    }
	    else
		l->v.i = -l->v.i;
	    break;
	case t_float:
	    l->v.d = -l->v.d;
	    break;
	case t_mpz:
	    mpz_neg(l->v.mpz, l->v.mpz);
	    break;
	case t_mpq:
	    mpq_neg(l->v.mpq, l->v.mpq);
	    break;
	case t_mpr:
	    mpfr_neg(l->v.mpr, l->v.mpr, thr_rnd);
	    break;
	case t_cdd:
	    l->v.cdd = -l->v.cdd;
	    break;
	case t_cqq:
	    cqq_neg(l->v.cqq, l->v.cqq);
	    break;
	default:
	    mpc_neg(l->v.mpc, l->v.mpc, thr_rndc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_signbit(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    l->v.i = l->v.i < 0;
	    break;
	case t_float:
	    l->v.i = signbit(l->v.d) != 0;
	    break;
	case t_mpz:
	    l->v.i = mpz_sgn(l->v.mpz) < 0;
	    break;
	case t_mpq:
	    l->v.i = mpq_sgn(l->v.mpq) < 0;
	    break;
	case t_mpr:
	    l->v.i = mpfr_signbit(l->v.mpr) != 0;
	    break;
	default:
	    ecfg_error(read, "not a real number");
    }
    l->t = t_int;
}

void
enumber_signum(evalue_t *l)
{
    /* signum(x) = x / abs(x) */
    switch (l->t) {
	case t_int:
	    l->v.i = ei_signum_i(l->v.i);
	    break;
	case t_float:
	    l->v.d = ed_signum_d(l->v.d);
	    break;
	case t_mpz:
	    l->v.i = ei_signum_z(l->v.mpz);
	    l->t = t_int;
	    break;
	case t_mpq:
	    l->v.i = ei_signum_q(l->v.mpq);
	    l->t = t_int;
	    break;
	case t_mpr:
	    er_signum_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = edd_signum_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_signum_qq(l->v.cqq);
		l->t = t_cqq;
	    }
	    else {
		ecc_signum_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_signum_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_rational(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_mpz:
	case t_mpq:
	    break;
	case t_float:
	    if (!finite(l->v.d))
		ecfg_error(read, "not a finite real number");
	    switch (eq_rational_d(thr_qr, l->v.d)) {
		case -1:
		    enew_mpz(&l->v.o, thr_zr);
		    l->t = t_mpz;
		    break;
		case 0:
		    enew_mpq(&l->v.o, thr_qr);
		    l->t = t_mpq;
		    break;
		default:
		    l->v.i = empz_get_i(thr_zr);
		    l->t = t_int;
		    break;
	    }
	    break;
	case t_mpr:
	    if (!mpfr_number_p(l->v.mpr))
		ecfg_error(read, "not a finite real number");
	    switch (eq_rational_r(thr_qr, l->v.mpr)) {
		case -1:
		    enew_mpz(&l->v.o, thr_zr);
		    l->t = t_mpz;
		    break;
		case 0:
		    enew_mpq(&l->v.o, thr_qr);
		    l->t = t_mpq;
		    break;
		default:
		    l->v.i = empz_get_i(thr_zr);
		    l->t = t_int;
		    break;
	    }
	    break;
	default:
	    ecfg_error(read, "not a real number");
    }
}

void
enumber_integer_p(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_mpz:
	    l->v.i = 1;
	    break;
	default:
	    l->v.i = 0;
	    break;
    }
    l->t = t_int;
}

void
enumber_rational_p(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_mpz:
	case t_mpq:
	    l->v.i = 1;
	    break;
	default:
	    l->v.i = 0;
	    break;
    }
    l->t = t_int;
}

void
enumber_float_p(evalue_t *l)
{
    switch (l->t) {
	case t_float:
	case t_mpr:
	    l->v.i = 1;
	    break;
	default:
	    l->v.i = 0;
	    break;
    }
    l->t = t_int;
}

void
enumber_real_p(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_float:
	case t_mpz:
	case t_mpq:
	case t_mpr:
	    l->v.i = 1;
	    break;
	default:
	    l->v.i = 0;
	    break;
    }
    l->t = t_int;
}

void
enumber_complex_p(evalue_t *l)
{
    switch (l->t) {
	case t_cdd:
	case t_cqq:
	case t_mpc:
	    l->v.i = 1;
	    break;
	default:
	    l->v.i = 0;
	    break;
    }
    l->t = t_int;
}

void
enumber_number_p(evalue_t *l)
{
    l->v.i = 1;
    l->t = t_int;
}

void
enumber_finite_p(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    l->v.i = 1;
	    break;
	case t_float:
	    l->v.i = finite(l->v.d) ? 1 : 0;
	    break;
	case t_mpz:
	    l->v.i = 1;
	    break;
	case t_mpq:
	    l->v.i = 1;
	    break;
	case t_mpr:
	    l->v.i = mpfr_number_p(l->v.mpr) ? 1 : 0;
	    break;
	default:
	    l->v.i = 0;
	    break;
    }
    l->t = t_int;
}

void
enumber_inf_p(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    l->v.i = 0;
	    break;
	case t_float:
	    l->v.i = isinf(l->v.d) ? signbit(l->v.d) ? -1 : 1 : 0;
	    break;
	case t_mpz:
	    l->v.i = 0;
	    break;
	case t_mpq:
	    l->v.i = 0;
	    break;
	case t_mpr:
	    l->v.i = mpfr_inf_p(l->v.mpr) ? mpfr_signbit(l->v.mpr) ? -1 : 1 : 0;
	    break;
	default:
	    l->v.i = 0;
	    break;
    }
    l->t = t_int;
}

void
enumber_nan_p(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    l->v.i = 0;
	    break;
	case t_float:
	    l->v.i = isnan(l->v.d) ? 1 : 0;
	    break;
	case t_mpz:
	    l->v.i = 0;
	    break;
	case t_mpq:
	    l->v.i = 0;
	    break;
	case t_mpr:
	    l->v.i = mpfr_nan_p(l->v.mpr) ? 1 : 0;
	    break;
	default:
	    l->v.i = 0;
	    break;
    }
    l->t = t_int;
}

void
enumber_num(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_mpz:
	    break;
	case t_mpq:
	    enew_mpz(&l->v.o, mpq_numref(l->v.mpq));
	    l->t = t_mpz;
	    break;
	default:
	    ecfg_error(read, "not a rational number");
    }
    number_canonicalize(l);
}

void
enumber_den(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_mpz:
	    l->t = t_int;
	    l->v.i = 1;
	    break;
	case t_mpq:
	    enew_mpz(&l->v.o, mpq_denref(l->v.mpq));
	    l->t = t_mpz;
	    break;
	default:
	    ecfg_error(read, "not a rational number");
    }
    number_canonicalize(l);
}

void
enumber_real(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_float:
	case t_mpz:
	case t_mpq:
	case t_mpr:
	    break;
	case t_cdd:
	    l->t = t_float;
	    break;
	case t_cqq:
	    enew_mpq(&l->v.o, cqq_realref(l->v.cqq));
	    l->t = t_mpq;
	    break;
	default:
	    enew_mpr(&l->v.o, mpc_realref(l->v.mpc));
	    l->t = t_mpr;
	    break;
    }
    number_canonicalize(l);
}

void
enumber_imag(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_float:
	case t_mpz:
	case t_mpq:
	case t_mpr:
	    l->v.i = 0;
	    l->t = t_int;
	    break;
	case t_cdd:
	    real(l->v.cdd) = imag(l->v.cdd);
	    l->t = t_float;
	    break;
	case t_cqq:
	    enew_mpq(&l->v.o, cqq_imagref(l->v.cqq));
	    l->t = t_mpq;
	    break;
	default:
	    enew_mpr(&l->v.o, mpc_imagref(l->v.mpc));
	    l->t = t_mpr;
	    break;
    }
    number_canonicalize(l);
}

void
enumber_arg(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (l->v.i >= 0) {
	    rational_arg_zero:
		if (!thread_self->flt) {
		    l->v.d = 0.0;
		    l->t = t_float;
		}
		else {
		    mpfr_set_ui(thr_rr, 0, thr_rnd);
		    enew_mpr(&l->v.o, thr_rr);
		    l->t = t_mpr;
		}
	    }
	    else {
	    rational_arg_pi:
		if (!thread_self->flt) {
		    l->v.d = M_PI;
		    l->t = t_float;
		}
		else {
		    mpfr_const_pi(thr_rr, thr_rnd);
		    enew_mpr(&l->v.o, thr_rr);
		    l->t = t_mpr;
		}
	    }
	    break;
	case t_float:
	    l->v.d = ed_arg_d(l->v.d);
	    break;
	case t_mpz:
	    if (mpz_sgn(l->v.mpz) >= 0)
		goto rational_arg_zero;
	    goto rational_arg_pi;
	case t_mpq:
	    if (mpq_sgn(l->v.mpq) >= 0)
		goto rational_arg_zero;
	    goto rational_arg_pi;
	    break;
	case t_mpr:
	    er_arg_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.d = ed_arg_dd(l->v.cdd);
	    l->t = t_float;
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.d = ed_arg_qq(l->v.cqq);
		l->t = t_float;
	    }
	    else {
		er_arg_qq(thr_rr, l->v.cqq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	default:
	    er_arg_cc(thr_rr, l->v.mpc);
	    enew_mpr(&l->v.o, thr_rr);
	    l->t = t_mpr;
	    break;
    }
}

void
enumber_conj(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_float:
	case t_mpz:
	case t_mpq:
	case t_mpr:
	    break;
	case t_cdd:
	    l->v.cdd = edd_conj_dd(l->v.cdd);
	    break;
	case t_cqq:
	    eqq_conj_qq(l->v.cqq, l->v.cqq);
	    break;
	default:
	    ecc_conj_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_floor(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_mpz:
	    break;
	case t_float:
	    l->v.d = floor(l->v.d);
	    if ((eint_t)l->v.d == l->v.d) {
		l->v.i = l->v.d;
		l->t = t_int;
	    }
	    else {
		l->v.mpz = new_mpz_d(l->v.d);
		l->t = t_mpz;
	    }
	    break;
	case t_mpq:
	    mpz_fdiv_q(thr_zr, mpq_numref(l->v.mpq), mpq_denref(l->v.mpq));
	    enew_mpz(&l->v.o, thr_zr);
	    l->t = t_mpz;
	    break;
	case t_mpr:
	    mpfr_floor(l->v.mpr, l->v.mpr);
	    l->v.mpz = new_mpz_r(l->v.mpr);
	    l->t = t_mpz;
	    break;
	default:
	    ecfg_error(read, "not a real number");
    }
    number_canonicalize(l);
}

void
enumber_trunc(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_mpz:
	    break;
	case t_float:
	    l->v.d = trunc(l->v.d);
	    if ((eint_t)l->v.d == l->v.d) {
		l->v.i = l->v.d;
		l->t = t_int;
	    }
	    else {
		l->v.mpz = new_mpz_d(l->v.d);
		l->t = t_mpz;
	    }
	    break;
	case t_mpq:
	    mpz_tdiv_q(thr_zr, mpq_numref(l->v.mpq), mpq_denref(l->v.mpq));
	    enew_mpz(&l->v.o, thr_zr);
	    l->t = t_mpz;
	    break;
	case t_mpr:
	    mpfr_trunc(l->v.mpr, l->v.mpr);
	    l->v.mpz = new_mpz_r(l->v.mpr);
	    l->t = t_mpz;
	    break;
	default:
	    ecfg_error(read, "not a real number");
    }
    number_canonicalize(l);
}

void
enumber_round(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_mpz:
	    break;
	case t_float:
	    l->v.d = round(l->v.d);
	    if ((eint_t)l->v.d == l->v.d) {
		l->v.i = l->v.d;
		l->t = t_int;
	    }
	    else {
		l->v.mpz = new_mpz_d(l->v.d);
		l->t = t_mpz;
	    }
	    break;
	case t_mpq:
	    if (mpq_sgn(l->v.mpq) > 0) {
		mpz_cdiv_qr(thr_zr, thr_z0,
			    mpq_numref(l->v.mpq), mpq_denref(l->v.mpq));
		mpz_mul_2exp(thr_z0, thr_z0, 1);
		if (mpz_cmpabs(thr_z0, mpq_denref(l->v.mpq)) > 0)
		    mpz_sub_ui(thr_zr, thr_zr, 1);
	    }
	    else {
		mpz_fdiv_qr(thr_zr, thr_z0,
			    mpq_numref(l->v.mpq), mpq_denref(l->v.mpq));
		mpz_mul_2exp(thr_z0, thr_z0, 1);
		if (mpz_cmpabs(thr_z0, mpq_denref(l->v.mpq)) > 0)
		    mpz_add_ui(thr_zr, thr_zr, 1);
	    }
	    enew_mpz(&l->v.o, thr_zr);
	    l->t = t_mpz;
	    break;
	case t_mpr:
	    mpfr_round(l->v.mpr, l->v.mpr);
	    l->v.mpz = new_mpz_r(l->v.mpr);
	    l->t = t_mpz;
	    break;
	default:
	    ecfg_error(read, "not a real number");
    }
    number_canonicalize(l);
}

void
enumber_ceil(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_mpz:
	    break;
	case t_float:
	    l->v.d = ceil(l->v.d);
	    if ((eint_t)l->v.d == l->v.d) {
		l->v.i = l->v.d;
		l->t = t_int;
	    }
	    else {
		l->v.mpz = new_mpz_d(l->v.d);
		l->t = t_mpz;
	    }
	    break;
	case t_mpq:
	    mpz_cdiv_q(thr_zr, mpq_numref(l->v.mpq), mpq_denref(l->v.mpq));
	    enew_mpz(&l->v.o, thr_zr);
	    l->t = t_mpz;
	    break;
	case t_mpr:
	    mpfr_ceil(l->v.mpr, l->v.mpr);
	    l->v.mpz = new_mpz_r(l->v.mpr);
	    l->t = t_mpz;
	    break;
	default:
	    ecfg_error(read, "not a real number");
    }
    number_canonicalize(l);
}

void
enumber_abs(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if ((l->v.i = ez_abs_i(thr_zr, l->v.i)) == MININT) {
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    break;
	case t_float:
	    l->v.d = ed_abs_d(l->v.d);
	    break;
	case t_mpz:
	    ez_abs_z(l->v.mpz, l->v.mpz);
	    break;
	case t_mpq:
	    eq_abs_q(l->v.mpq, l->v.mpq);
	    break;
	case t_mpr:
	    er_abs_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.d = ed_abs_dd(l->v.cdd);
	    l->t = t_float;
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.d = ed_abs_qq(l->v.cqq);
		l->t = t_float;
	    }
	    else {
		er_abs_qq(thr_rr, l->v.cqq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	default:
	    er_abs_cc(thr_rr, l->v.mpc);
	    enew_mpr(&l->v.o, thr_rr);
	    break;
    }
}

void
enumber_sqrt(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		if (l->v.i >= 0) {
		    l->v.d = ed_sqrt_i(l->v.i);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_sqrt_i(l->v.i);
		    l->t = t_cdd;
		}
	    }
	    else if (l->v.i >= 0) {
		er_sqrt_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_sqrt_i(thr_c, l->v.i);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_float:
	    if (!isnan(l->v.d)) {
		if (l->v.d >= 0)
		    l->v.d = ed_sqrt_d(l->v.d);
		else {
		    l->v.cdd = edd_sqrt_dd(l->v.d);
		    l->t = t_cdd;
		}
	    }
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		if (mpz_sgn(l->v.mpz) > 0) {
		    l->v.d = ed_sqrt_z(l->v.mpz);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_sqrt_z(l->v.mpz);
		    l->t = t_cdd;
		}
	    }
	    else if (mpz_sgn(l->v.mpz) > 0) {
		er_sqrt_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_sqrt_z(thr_c, l->v.mpz);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		if (mpq_sgn(l->v.mpq) > 0) {
		    l->v.d = ed_sqrt_q(l->v.mpq);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_sqrt_q(l->v.mpq);
		    l->t = t_cdd;
		}
	    }
	    else if (mpq_sgn(l->v.mpq) > 0) {
		er_sqrt_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_sqrt_q(thr_c, l->v.mpq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpr:
	    if (!mpfr_nan_p(l->v.mpr)) {
		if (mpfr_sgn(l->v.mpr) >= 0)
		    er_sqrt_r(l->v.mpr, l->v.mpr);
		else {
		    ecc_sqrt_r(thr_c, l->v.mpr);
		    enew_mpc(&l->v.o, thr_c);
		    l->t = t_mpc;
		}
	    }
	    break;
	case t_cdd:
	    l->v.cdd = edd_sqrt_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_sqrt_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_sqrt_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_sqrt_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_cbrt(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		l->v.d = ed_cbrt_i(l->v.i);
		l->t = t_float;
	    }
	    else {
		er_cbrt_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_float:
	    l->v.d = ed_cbrt_d(l->v.d);
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.d = ed_cbrt_z(l->v.mpz);
		l->t = t_float;
	    }
	    else {
		er_cbrt_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		l->v.d = ed_cbrt_q(l->v.mpq);
		l->t = t_float;
	    }
	    else {
		er_cbrt_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpr:
	    er_cbrt_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = edd_cbrt_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_cbrt_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_cbrt_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_cbrt_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_sin(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		l->v.d = ed_sin_i(l->v.i);
		l->t = t_float;
	    }
	    else {
		er_sin_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_float:
	    l->v.d = ed_sin_d(l->v.d);
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.d = ed_sin_z(l->v.mpz);
		l->t = t_float;
	    }
	    else {
		er_sin_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		l->v.d = ed_sin_q(l->v.mpq);
		l->t = t_float;
	    }
	    else {
		er_sin_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpr:
	    er_sin_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = edd_sin_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_sin_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_sin_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_sin_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_cos(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		l->v.d = ed_cos_i(l->v.i);
		l->t = t_float;
	    }
	    else {
		er_cos_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_float:
	    l->v.d = ed_cos_d(l->v.d);
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.d = ed_cos_z(l->v.mpz);
		l->t = t_float;
	    }
	    else {
		er_cos_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		l->v.d = ed_cos_q(l->v.mpq);
		l->t = t_float;
	    }
	    else {
		er_cos_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpr:
	    er_cos_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = edd_cos_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_cos_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_cos_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_cos_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_tan(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		l->v.d = ed_tan_i(l->v.i);
		l->t = t_float;
	    }
	    else {
		er_tan_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_float:
	    l->v.d = ed_tan_d(l->v.d);
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.d = ed_tan_z(l->v.mpz);
		l->t = t_float;
	    }
	    else {
		er_tan_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		l->v.d = ed_tan_q(l->v.mpq);
		l->t = t_float;
	    }
	    else {
		er_tan_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpr:
	    er_tan_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = edd_tan_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_tan_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_tan_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_tan_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_asin(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		if (l->v.i >= -1 && l->v.i <= 1) {
		    l->v.d = ed_asin_i(l->v.i);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_asin_i(l->v.i);
		    l->t = t_cdd;
		}
	    }
	    else if (l->v.i >= -1 && l->v.i <= 1) {
		er_asin_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_asin_i(thr_c, l->v.i);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_float:
	    if (!isnan(l->v.d)) {
		if (fabs(l->v.d) <= 1.0)
		    l->v.d = ed_asin_d(l->v.d);
		else {
		    l->v.cdd = edd_asin_d(l->v.d);
		    l->t = t_cdd;
		}
	    }
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.cdd = edd_asin_z(l->v.mpz);
		l->t = t_cdd;
	    }
	    else {
		ecc_asin_z(thr_c, l->v.mpz);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		if ((mpq_sgn(l->v.mpq) >= 0 &&
		     mpq_cmp_ui(l->v.mpq, 1, 1) <= 0) ||
		    (mpq_sgn(l->v.mpq) < 0 &&
		     mpq_cmp_si(l->v.mpq, -1, 1) >= 0)) {
		    l->v.d = ed_asin_q(l->v.mpq);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_asin_q(l->v.mpq);
		    l->t = t_cdd;
		}
	    }
	    else if ((mpq_sgn(l->v.mpq) >= 0 &&
		      mpq_cmp_ui(l->v.mpq, 1, 1) <= 0) ||
		     (mpq_sgn(l->v.mpq) < 0 &&
		      mpq_cmp_si(l->v.mpq, -1, 1) >= 0)) {
		er_asin_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_asin_z(thr_c, l->v.mpz);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpr:
	    if (!mpfr_nan_p(l->v.mpr)) {
		if ((mpfr_sgn(l->v.mpr) >= 0 &&
		     mpfr_cmp_ui(l->v.mpr, 1) <= 0) ||
		    (mpfr_sgn(l->v.mpr) < 0 &&
		     mpfr_cmp_si(l->v.mpr, -1) >= 0))
		    er_asin_r(l->v.mpr, l->v.mpr);
		else {
		    ecc_asin_r(thr_c, l->v.mpr);
		    enew_mpc(&l->v.o, thr_c);
		    l->t = t_mpc;
		}
	    }
	    break;
	case t_cdd:
	    l->v.cdd = edd_asin_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_asin_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_asin_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_asin_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_acos(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		if (l->v.i >= -1 && l->v.i <= 1) {
		    l->v.d = ed_acos_i(l->v.i);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_acos_i(l->v.i);
		    l->t = t_cdd;
		}
	    }
	    else if (l->v.i >= -1 && l->v.i <= 1) {
		er_acos_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_acos_i(thr_c, l->v.i);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_float:
	    if (!isnan(l->v.d)) {
		if (fabs(l->v.d) <= 1.0)
		    l->v.d = ed_acos_d(l->v.d);
		else {
		    l->v.cdd = edd_acos_d(l->v.d);
		    l->t = t_cdd;
		}
	    }
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.cdd = edd_acos_z(l->v.mpz);
		l->t = t_cdd;
	    }
	    else {
		ecc_acos_z(thr_c, l->v.mpz);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		if ((mpq_sgn(l->v.mpq) >= 0 &&
		     mpq_cmp_ui(l->v.mpq, 1, 1) <= 0) ||
		    (mpq_sgn(l->v.mpq) < 0 &&
		     mpq_cmp_si(l->v.mpq, -1, 1) >= 0)) {
		    l->v.d = ed_acos_q(l->v.mpq);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_acos_q(l->v.mpq);
		    l->t = t_cdd;
		}
	    }
	    else if ((mpq_sgn(l->v.mpq) >= 0 &&
		      mpq_cmp_ui(l->v.mpq, 1, 1) <= 0) ||
		     (mpq_sgn(l->v.mpq) < 0 &&
		      mpq_cmp_si(l->v.mpq, -1, 1) >= 0)) {
		er_acos_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_acos_z(thr_c, l->v.mpz);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpr:
	    if (!mpfr_nan_p(l->v.mpr)) {
		if ((mpfr_sgn(l->v.mpr) >= 0 &&
		     mpfr_cmp_ui(l->v.mpr, 1) <= 0) ||
		    (mpfr_sgn(l->v.mpr) < 0 &&
		     mpfr_cmp_si(l->v.mpr, -1) >= 0))
		    er_acos_r(l->v.mpr, l->v.mpr);
		else {
		    ecc_acos_r(thr_c, l->v.mpr);
		    enew_mpc(&l->v.o, thr_c);
		    l->t = t_mpc;
		}
	    }
	    break;
	case t_cdd:
	    l->v.cdd = edd_acos_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_acos_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_acos_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_acos_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_atan(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		l->v.d = ed_atan_i(l->v.i);
		l->t = t_float;
	    }
	    else {
		er_atan_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_float:
	    l->v.d = ed_atan_d(l->v.d);
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.d = ed_atan_z(l->v.mpz);
		l->t = t_float;
	    }
	    else {
		er_atan_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		l->v.d = ed_atan_q(l->v.mpq);
		l->t = t_float;
	    }
	    else {
		er_atan_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpr:
	    er_atan_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = edd_atan_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_atan_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_atan_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_atan_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_sinh(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		l->v.d = ed_sinh_i(l->v.i);
		l->t = t_float;
	    }
	    else {
		er_sinh_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_float:
	    l->v.d = ed_sinh_d(l->v.d);
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.d = ed_sinh_z(l->v.mpz);
		l->t = t_float;
	    }
	    else {
		er_sinh_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		l->v.d = ed_sinh_q(l->v.mpq);
		l->t = t_float;
	    }
	    else {
		er_sinh_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpr:
	    er_sinh_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = edd_sinh_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_sinh_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_sinh_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_sinh_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_cosh(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		l->v.d = ed_cosh_i(l->v.i);
		l->t = t_float;
	    }
	    else {
		er_cosh_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_float:
	    l->v.d = ed_cosh_d(l->v.d);
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.d = ed_cosh_z(l->v.mpz);
		l->t = t_float;
	    }
	    else {
		er_cosh_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		l->v.d = ed_cosh_q(l->v.mpq);
		l->t = t_float;
	    }
	    else {
		er_cosh_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpr:
	    er_cosh_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = edd_cosh_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_cosh_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_cosh_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_cosh_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_tanh(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		l->v.d = ed_tanh_i(l->v.i);
		l->t = t_float;
	    }
	    else {
		er_tanh_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_float:
	    l->v.d = ed_tanh_d(l->v.d);
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.d = ed_tanh_z(l->v.mpz);
		l->t = t_float;
	    }
	    else {
		er_tanh_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		l->v.d = ed_tanh_q(l->v.mpq);
		l->t = t_float;
	    }
	    else {
		er_tanh_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpr:
	    er_tanh_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = edd_tanh_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_tanh_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_tanh_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_tanh_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_asinh(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		l->v.d = ed_asinh_i(l->v.i);
		l->t = t_float;
	    }
	    else {
		er_asinh_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_float:
	    l->v.d = ed_asinh_d(l->v.d);
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.d = ed_asinh_z(l->v.mpz);
		l->t = t_float;
	    }
	    else {
		er_asinh_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		l->v.d = ed_asinh_q(l->v.mpq);
		l->t = t_float;
	    }
	    else {
		er_asinh_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpr:
	    er_asinh_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = edd_asinh_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_asinh_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_asinh_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_asinh_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_acosh(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		if (l->v.i >= 1) {
		    l->v.d = ed_acosh_i(l->v.i);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_acosh_i(l->v.i);
		    l->t = t_cdd;
		}
	    }
	    else if (l->v.i >= 1) {
		er_acosh_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_acosh_i(thr_c, l->v.i);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_float:
	    if (!isnan(l->v.d)) {
		if (l->v.d >= 1.0)
		    l->v.d = ed_acosh_d(l->v.d);
		else {
		    l->v.cdd = edd_acosh_d(l->v.d);
		    l->t = t_cdd;
		}
	    }
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		if (mpz_sgn(l->v.mpz) > 0) {
		    l->v.d = ed_acosh_z(l->v.mpz);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_acosh_z(l->v.mpz);
		    l->t = t_cdd;
		}
	    }
	    else if (mpz_sgn(l->v.mpz) > 0) {
		er_acosh_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_acosh_z(thr_c, l->v.mpz);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		if (mpq_cmp_ui(l->v.mpq, 1, 1) >= 0) {
		    l->v.d = ed_acosh_q(l->v.mpq);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_acosh_q(l->v.mpq);
		    l->t = t_cdd;
		}
	    }
	    else if (mpq_cmp_ui(l->v.mpq, 1, 1) >= 0) {
		er_acosh_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_acosh_q(thr_c, l->v.mpq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpr:
	    if (!mpfr_nan_p(l->v.mpr)) {
		if (mpfr_cmp_ui(l->v.mpr, 1) >= 0)
		    er_acosh_r(l->v.mpr, l->v.mpr);
		else {
		    ecc_acosh_r(thr_c, l->v.mpr);
		    enew_mpc(&l->v.o, thr_c);
		    l->t = t_mpc;
		}
	    }
	    break;
	case t_cdd:
	    l->v.cdd = edd_acosh_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_acosh_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_acosh_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_acosh_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_atanh(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		if (l->v.i < -1 && l->v.i < 1) {
		    l->v.d = ed_atanh_i(l->v.i);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_atanh_i(l->v.i);
		    l->t = t_cdd;
		}
	    }
	    else if (l->v.i < -1 && l->v.i < 1) {
		er_atanh_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_atanh_i(thr_c, l->v.i);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_float:
	    if (!isnan(l->v.d)) {
		if (fabs(l->v.d) < 1.0)
		    l->v.d = ed_atanh_d(l->v.d);
		else {
		    l->v.cdd = edd_atanh_d(l->v.d);
		    l->t = t_cdd;
		}
	    }
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.cdd = edd_atanh_z(l->v.mpz);
		l->t = t_cdd;
	    }
	    else {
		ecc_atanh_z(thr_c, l->v.mpz);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		if ((mpq_sgn(l->v.mpq) >= 0 &&
		     mpq_cmp_ui(l->v.mpq, 1, 1) < 0) ||
		    (mpq_sgn(l->v.mpq) < 0 &&
		     mpq_cmp_si(l->v.mpq, -1, 1) > 0)) {
		    l->v.d = ed_atanh_q(l->v.mpq);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_atanh_q(l->v.mpq);
		    l->t = t_cdd;
		}
	    }
	    else if ((mpq_sgn(l->v.mpq) >= 0 &&
		      mpq_cmp_ui(l->v.mpq, 1, 1) < 0) ||
		     (mpq_sgn(l->v.mpq) < 0 &&
		      mpq_cmp_si(l->v.mpq, -1, 1) > 0)) {
		er_atanh_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_atanh_q(thr_c, l->v.mpq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpr:
	    if (!mpfr_nan_p(l->v.mpr)) {
		if ((mpfr_sgn(l->v.mpr) >= 0 &&
		     mpfr_cmp_ui(l->v.mpr, 1) < 0) ||
		    (mpfr_sgn(l->v.mpr) < 0 &&
		     mpfr_cmp_si(l->v.mpr, -1) > 0))
		    er_atanh_r(l->v.mpr, l->v.mpr);
		else {
		    ecc_atanh_r(thr_c, l->v.mpr);
		    enew_mpc(&l->v.o, thr_c);
		    l->t = t_mpc;
		}
	    }
	    break;
	case t_cdd:
	    l->v.cdd = edd_atanh_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_atanh_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_atanh_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_atanh_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_proj(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	case t_mpz:
	case t_mpq:
	case t_cqq:
	    break;
	case t_float:
	    l->v.d = ed_proj_d(l->v.d);
	    break;
	case t_mpr:
	    er_proj_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = edd_proj_dd(l->v.cdd);
	    break;
	default:
	    ecc_proj_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_exp(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		l->v.d = ed_exp_i(l->v.i);
		l->t = t_float;
	    }
	    else {
		er_exp_i(thr_rr, l->v.i);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_float:
	    l->v.d = ed_exp_d(l->v.d);
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		l->v.d = ed_exp_z(l->v.mpz);
		l->t = t_float;
	    }
	    else {
		er_exp_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		l->v.d = ed_exp_q(l->v.mpq);
		l->t = t_float;
	    }
	    else {
		er_exp_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    break;
	case t_mpr:
	    er_exp_r(l->v.mpr, l->v.mpr);
	    break;
	case t_cdd:
	    l->v.cdd = edd_exp_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_exp_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_exp_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_exp_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_log(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		if (l->v.i >= 0) {
		    l->v.d = ed_log_i(l->v.i);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_log_i(l->v.i);
		    l->t = t_cdd;
		}
	    }
	    else {
		if (l->v.i >= 0) {
		    er_log_i(thr_rr, l->v.i);
		    enew_mpr(&l->v.o, thr_rr);
		    l->t = t_mpr;
		}
		else {
		    ecc_log_i(thr_c, l->v.i);
		    enew_mpc(&l->v.o, thr_c);
		    l->t = t_mpc;
		}
	    }
	    break;
	case t_float:
	    if (!isnan(l->v.d)) {
		if (l->v.d >= 0.0)
		    l->v.d = ed_log_d(l->v.d);
		else {
		    l->v.cdd = edd_log_d(l->v.d);
		    l->t = t_cdd;
		}
	    }
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		if (mpz_sgn(l->v.mpz) >= 0) {
		    l->v.d = ed_log_z(l->v.mpz);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_log_z(l->v.mpz);
		    l->t = t_cdd;
		}
	    }
	    else if (mpz_sgn(l->v.mpz) >= 0) {
		er_log_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_log_z(thr_c, l->v.mpz);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		if (mpq_sgn(l->v.mpq) >= 0) {
		    l->v.d = ed_log_q(l->v.mpq);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_log_q(l->v.mpq);
		    l->t = t_cdd;
		}
	    }
	    else if (mpq_sgn(l->v.mpq) >= 0) {
		er_log_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_log_q(thr_c, l->v.mpq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpr:
	    if (!mpfr_nan_p(l->v.mpr)) {
		if (mpfr_sgn(l->v.mpr) >= 0)
		    er_log_r(l->v.mpr, l->v.mpr);
		else {
		    ecc_log_r(thr_c, l->v.mpr);
		    enew_mpc(&l->v.o, thr_c);
		    l->t = t_mpc;
	    }}
	    break;
	case t_cdd:
	    l->v.cdd = edd_log_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_log_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_log_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_log_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_log2(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		if (l->v.i >= 0) {
		    l->v.d = ed_log2_i(l->v.i);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_log2_i(l->v.i);
		    l->t = t_cdd;
		}
	    }
	    else {
		if (l->v.i >= 0) {
		    er_log2_i(thr_rr, l->v.i);
		    enew_mpr(&l->v.o, thr_rr);
		    l->t = t_mpr;
		}
		else {
		    ecc_log2_i(thr_c, l->v.i);
		    enew_mpc(&l->v.o, thr_c);
		    l->t = t_mpc;
		}
	    }
	    break;
	case t_float:
	    if (!isnan(l->v.d)) {
		if (l->v.d >= 0.0)
		    l->v.d = ed_log2_d(l->v.d);
		else {
		    l->v.cdd = edd_log2_d(l->v.d);
		    l->t = t_cdd;
		}
	    }
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		if (mpz_sgn(l->v.mpz) >= 0) {
		    l->v.d = ed_log2_z(l->v.mpz);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_log2_z(l->v.mpz);
		    l->t = t_cdd;
		}
	    }
	    else if (mpz_sgn(l->v.mpz) >= 0) {
		er_log2_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_log2_z(thr_c, l->v.mpz);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		if (mpq_sgn(l->v.mpq) >= 0) {
		    l->v.d = ed_log2_q(l->v.mpq);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_log2_q(l->v.mpq);
		    l->t = t_cdd;
		}
	    }
	    else if (mpq_sgn(l->v.mpq) >= 0) {
		er_log2_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_log2_q(thr_c, l->v.mpq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpr:
	    if (!mpfr_nan_p(l->v.mpr)) {
		if (mpfr_sgn(l->v.mpr) >= 0)
		    er_log2_r(l->v.mpr, l->v.mpr);
		else {
		    ecc_log2_r(thr_c, l->v.mpr);
		    enew_mpc(&l->v.o, thr_c);
		    l->t = t_mpc;
	    }}
	    break;
	case t_cdd:
	    l->v.cdd = edd_log2_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_log2_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_log2_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_log2_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

void
enumber_log10(evalue_t *l)
{
    switch (l->t) {
	case t_int:
	    if (!thread_self->flt) {
		if (l->v.i >= 0) {
		    l->v.d = ed_log10_i(l->v.i);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_log10_i(l->v.i);
		    l->t = t_cdd;
		}
	    }
	    else {
		if (l->v.i >= 0) {
		    er_log10_i(thr_rr, l->v.i);
		    enew_mpr(&l->v.o, thr_rr);
		    l->t = t_mpr;
		}
		else {
		    ecc_log10_i(thr_c, l->v.i);
		    enew_mpc(&l->v.o, thr_c);
		    l->t = t_mpc;
		}
	    }
	    break;
	case t_float:
	    if (!isnan(l->v.d)) {
		if (l->v.d >= 0.0)
		    l->v.d = ed_log10_d(l->v.d);
		else {
		    l->v.cdd = edd_log10_d(l->v.d);
		    l->t = t_cdd;
		}
	    }
	    break;
	case t_mpz:
	    if (!thread_self->flt) {
		if (mpz_sgn(l->v.mpz) >= 0) {
		    l->v.d = ed_log10_z(l->v.mpz);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_log10_z(l->v.mpz);
		    l->t = t_cdd;
		}
	    }
	    else if (mpz_sgn(l->v.mpz) >= 0) {
		er_log10_z(thr_rr, l->v.mpz);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_log10_z(thr_c, l->v.mpz);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpq:
	    if (!thread_self->flt) {
		if (mpq_sgn(l->v.mpq) >= 0) {
		    l->v.d = ed_log10_q(l->v.mpq);
		    l->t = t_float;
		}
		else {
		    l->v.cdd = edd_log10_q(l->v.mpq);
		    l->t = t_cdd;
		}
	    }
	    else if (mpq_sgn(l->v.mpq) >= 0) {
		er_log10_q(thr_rr, l->v.mpq);
		enew_mpr(&l->v.o, thr_rr);
		l->t = t_mpr;
	    }
	    else {
		ecc_log10_q(thr_c, l->v.mpq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	case t_mpr:
	    if (!mpfr_nan_p(l->v.mpr)) {
		if (mpfr_sgn(l->v.mpr) >= 0)
		    er_log10_r(l->v.mpr, l->v.mpr);
		else {
		    ecc_log10_r(thr_c, l->v.mpr);
		    enew_mpc(&l->v.o, thr_c);
		    l->t = t_mpc;
	    }}
	    break;
	case t_cdd:
	    l->v.cdd = edd_log10_dd(l->v.cdd);
	    break;
	case t_cqq:
	    if (!thread_self->flt) {
		l->v.cdd = edd_log10_qq(l->v.cqq);
		l->t = t_cdd;
	    }
	    else {
		ecc_log10_qq(thr_c, l->v.cqq);
		enew_mpc(&l->v.o, thr_c);
		l->t = t_mpc;
	    }
	    break;
	default:
	    ecc_log10_cc(l->v.mpc, l->v.mpc);
	    break;
    }
    number_canonicalize(l);
}

/*
 * static functions
 */
static eint32_t
shift_power(evalue_t *v)
{
    eint32_t	o;
    switch (v->t) {
	case t_int:
	    o = v->v.i;
	    if (v->v.i != o || o == MININT32)
		goto invarg;
	    break;
	case t_float:
	    o = v->v.d;
	    if (v->v.d != o || o == MININT32)
		goto invarg;
	    break;
	case t_mpr:
	    if (!mpfr_integer_p(v->v.mpr) ||
		!mpfr_fits_sint_p(v->v.mpr, GMP_RNDZ) ||
		(o = empr_get_i(v->v.mpr)) == MININT32)
		goto invarg;
	    break;
	default:
	invarg:
	    ecfg_error(read, "not a 32 bits integer");
    }
    return (o);
}

static void
shift_mul(evalue_t *l, eint32_t o)
{
    switch (l->t) {
	case t_int:
	    if ((l->v.i = ez_mul2_i_i(thr_zr, l->v.i, o)) == MININT) {
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    break;
	case t_float:
	    l->v.d = ef_mul2_d_i(l->v.d, o);
	    break;
	case t_mpz:
	    ez_mul2_z_i(l->v.mpz, l->v.mpz, o);
	    break;
	case t_mpq:
	    switch (eq_mul2_q_i(l->v.mpq, l->v.mpq, o)) {
		case 0:
		    break;
		case 1:
		    l->v.i = empz_get_i(mpq_numref(l->v.mpq));
		    l->t = t_int;
		    break;
		default:
		    enew_mpz(&l->v.o, mpq_numref(l->v.mpq));
		    l->t = t_mpz;
		    break;
	    }
	    break;
	case t_mpr:
	    er_mul2_r_i(l->v.mpr, l->v.mpr, o);
	    break;
	case t_cdd:
	    l->v.cdd = edd_mul2_dd_i(l->v.cdd, o);
	    break;
	case t_cqq:
	    eqq_mul2_qq_i(l->v.cqq, l->v.cqq, o);
	    break;
	default:
	    ecc_mul2_cc_i(l->v.mpc, l->v.mpc, o);
	    break;
    }
}

static void
shift_div(evalue_t *l, eint32_t o)
{
    switch (l->t) {
	case t_int:
	    if (o) {
		if ((l->v.i = eq_div2_i_i(thr_qr, l->v.i, o)) == MININT) {
		    enew_mpq(&l->v.o, thr_qr);
		    l->t = t_mpq;
		}
	    }
	    break;
	case t_float:
	    l->v.d = ldexp(l->v.d, -o);
	    break;
	case t_mpz:
	    switch (eq_div2_z_i(thr_qr, l->v.mpz, o)) {
		case 0:
		    enew_mpq(&l->v.o, thr_qr);
		    l->t = t_mpq;
		    break;
		case 1:
		    l->v.i = empz_get_i(thr_zr);
		    l->t = t_int;
		    break;
		default:
		    mpz_set(l->v.mpz, thr_zr);
		    break;
	    }
	    break;
	case t_mpq:
	    switch (eq_div2_q_i(l->v.mpq, l->v.mpq, o)) {
		case 0:
		    break;
		case 1:
		    l->v.i = empz_get_i(mpq_numref(l->v.mpq));
		    l->t = t_int;
		    break;
		default:
		    enew_mpz(&l->v.o, mpq_numref(l->v.mpq));
		    l->t = t_mpz;
		    break;
	    }
	    break;
	case t_mpr:
	    er_div2_r_i(l->v.mpr, l->v.mpr, o);
	    break;
	case t_cdd:
	    l->v.cdd = edd_div2_dd_i(l->v.cdd, o);
	    break;
	case t_cqq:
	    eqq_div2_qq_i(l->v.cqq, l->v.cqq, o);
	    break;
	default:
	    ecc_div2_cc_i(l->v.mpc, l->v.mpc, o);
	    break;
    }
}

static void
shift_shl(evalue_t *l, eint32_t o)
{
    switch (l->t) {
	case t_int:
	    if ((l->v.i = ez_shl_i_i(thr_zr, l->v.i, o)) == MININT) {
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    break;
	case t_float:
	    if (ez_shl_d_i(thr_zr, l->v.d, o)) {
		l->v.i = empz_get_i(thr_zr);
		l->t = t_int;
	    }
	    else {
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    break;
	case t_mpz:
	    ez_shl_z_i(l->v.mpz, l->v.mpz, o);
	    break;
	case t_mpq:
	    if (ez_shl_q_i(thr_zr, l->v.mpq, o)) {
		l->v.i = empz_get_i(thr_zr);
		l->t = t_int;
	    }
	    else {
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    break;
	case t_mpr:
	    if (ez_shl_q_i(thr_zr, l->v.mpq, o)) {
		l->v.i = empz_get_i(thr_zr);
		l->t = t_int;
	    }
	    else {
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    break;
	default:
	    ecfg_error(read, "not a real number");
    }
}

static void
shift_shr(evalue_t *l, eint32_t o)
{
    switch (l->t) {
	case t_int:
	    if (o < 64)
		l->v.i >>= o;
	    else
		l->v.i >>= 63;
	    break;
	case t_float:
	    if ((l->v.i = ez_shr_d_i(thr_zr, l->v.d, o)) == MININT) {
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    else
		l->t = t_int;
	    break;
	case t_mpz:
	    if (ez_shr_z_i(l->v.mpz, l->v.mpz, o)) {
		l->v.i = empz_get_i(l->v.mpz);
		l->t = t_int;
	    }
	    break;
	case t_mpq:
	    if (ez_shr_q_i(thr_zr, l->v.mpq, o)) {
		l->v.i = empz_get_i(thr_zr);
		l->t = t_int;
	    }
	    else {
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    break;
	case t_mpr:
	    if (ez_shr_r_i(thr_zr, l->v.mpr, o)) {
		l->v.i = empz_get_i(thr_zr);
		l->t = t_int;
	    }
	    else {
		enew_mpz(&l->v.o, thr_zr);
		l->t = t_mpz;
	    }
	    break;
	default:
	    ecfg_error(read, "not a real number");
    }
}

static void
number_canonicalize(evalue_t *l)
{
    switch (l->t) {
	case t_mpz:
	    if (empz_fit_i(l->v.mpz)) {
		l->v.i = empz_get_i(l->v.mpz);
		l->t = t_int;
	    }
	    break;
	case t_cqq:
	    if (mpq_sgn(cqq_imagref(l->v.cqq)))
		break;
	    v_check(1);
	    v_push(l->v.o);
	    enew_mpq(&l->v.o, cqq_realref(l->v.cqq));
	    l->t = t_mpq;
	    v_dec();
	case t_mpq:
	    if (!mpz_cmp_ui(mpq_denref(l->v.mpq), 1)) {
		if (empz_fit_i(mpq_numref(l->v.mpq))) {
		    l->v.i = empz_get_i(mpq_numref(l->v.mpq));
		    l->t = t_int;
		}
		else {
		    v_check(1);
		    v_push(l->v.o);
		    enew_mpz(&l->v.o, mpq_numref(l->v.mpq));
		    l->t = t_mpz;
		    v_dec();
		}
	    }
	    break;
	case t_cdd:
	    if (imag(l->v.cdd) == 0)
		l->t = t_float;
	    break;
	case t_mpc:
	    if (mpfr_zero_p(mpc_imagref(l->v.mpc))) {
		v_check(1);
		v_push(l->v.o);
		enew_mpr(&l->v.o, mpc_realref(l->v.mpc));
		l->t = t_mpr;
		v_dec();
	    }
	    break;
	default:
	    break;
    }
}

static eobject_t
new_mpz_d(efloat_t d)
{
    empz_t	z;

    mpz_set_d(thr_zr, d);
    enew_mpz((eobject_t *)&z, thr_zr);

    return (z);
}

static eobject_t
new_mpz_r(empr_t r)
{
    empz_t	z;

    empz_set_r(thr_zr, r);
    enew_mpz((eobject_t *)&z, thr_zr);

    return (z);
}

static eobject_t
new_mpq_i(eint_t i)
{
    empq_t	q;

    empz_set_i(thr_zr, i);
    mpz_set_ui(mpq_denref(thr_qr), 1);
    enew_mpq((eobject_t *)&q, thr_qr);

    return (q);
}

static eobject_t
new_mpq_z(empz_t z)
{
    empq_t	q;

    mpq_set_z(thr_qr, z);
    enew_mpq((eobject_t *)&q, thr_qr);

    return (q);
}

static eobject_t
new_mpr_si(eint_t i)
{
    empr_t	r;

    empr_set_i(thr_rr, i);
    enew_mpr((eobject_t *)&r, thr_rr);

    return (r);
}

static eobject_t
new_mpr_d(efloat_t d)
{
    empr_t	r;

    mpfr_set_d(thr_rr, d, thr_rnd);
    enew_mpr((eobject_t *)&r, thr_rr);

    return (r);
}

static eobject_t
new_mpr_z(empz_t z)
{
    empr_t	r;

    mpfr_set_z(thr_rr, z, thr_rnd);
    enew_mpr((eobject_t *)&r, thr_rr);

    return (r);
}

static eobject_t
new_mpr_q(empq_t q)
{
    empr_t	r;

    mpfr_set_q(thr_rr, q, thr_rnd);
    enew_mpr((eobject_t *)&r, thr_rr);

    return (r);
}

static eobject_t
new_cqq_i_i(eint_t re, eint_t im)
{
    ecqq_t	qq;

    empz_set_i(thr_zr, re);
    mpz_set_ui(mpq_denref(thr_qr), 1);
    empz_set_i(mpq_numref(thr_qi), im);
    mpz_set_ui(mpq_denref(thr_qi), 1);
    enew_cqq((eobject_t *)&qq, thr_qq);

    return (qq);
}

static eobject_t
new_cqq_z_z(empz_t re, empz_t im)
{
    ecqq_t	qq;

    mpq_set_z(thr_qr, re);
    if (im)
	mpq_set_z(thr_qi, im);
    else
	mpq_set_ui(thr_qi, 0, 1);
    enew_cqq((eobject_t *)&qq, thr_qq);

    return (qq);
}

static eobject_t
new_cqq_q_q(empq_t re, empq_t im)
{
    ecqq_t	qq;

    mpq_set(thr_qr, re);
    if (im)
	mpq_set(thr_qi, im);
    else
	mpq_set_ui(thr_qi, 0, 1);
    enew_cqq((eobject_t *)&qq, thr_qq);

    return (qq);
}

static eobject_t
new_mpc_i_i(eint_t re, eint_t im)
{
    empc_t	c;

    empr_set_i(thr_rr, re);
    empr_set_i(thr_ri, im);
    enew_mpc((eobject_t *)&c, thr_c);

    return (c);
}

static eobject_t
new_mpc_d_d(efloat_t re, efloat_t im)
{
    empc_t	c;

    mpc_set_d_d(thr_c, re, im, thr_rndc);
    enew_mpc((eobject_t *)&c, thr_c);

    return (c);
}

static eobject_t
new_mpc_z(empz_t z)
{
    empc_t	c;

    mpc_set_z(thr_c, z, thr_rndc);
    enew_mpc((eobject_t *)&c, thr_c);

    return (c);
}

static eobject_t
new_mpc_q_q(empq_t re, empq_t im)
{
    empc_t	c;

    if (im)
	mpc_set_q_q(thr_c, re, im, thr_rndc);
    else
	mpc_set_q(thr_c, re, thr_rndc);
    enew_mpc((eobject_t *)&c, thr_c);

    return (c);
}

static eobject_t
new_mpc_r_r(empr_t re, empr_t im)
{
    empc_t	c;

    if (im)
	mpc_set_fr_fr(thr_c, re, im, thr_rndc);
    else
	mpc_set_fr(thr_c, re, thr_rndc);
    enew_mpc((eobject_t *)&c, thr_c);

    return (c);
}
